#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <ctype.h>

#define SIZE 1024
#define STREND '\0'

#define NONE_REDIR  -1
#define STDIN_REDIR  0
#define STDOUT_REDIR 1
#define APPEND_REDIR 2

#define IgnSpace(pos) do{while(isspace(commend[pos])){pos++;}}while(0)


char commend[SIZE];
char* argv[100];
char pwd[SIZE];
int flag = 0;//内建命令标识符
int status = 0;
int redir = NONE_REDIR;
char* filepath;
const char* HOSTNAME(){return getenv("HOSTNAME");}
const char* USER(){return getenv("USER");}
const char* PWD(){return getenv("PWD");}
char* HOME(){return getenv("HOME");}
char CMD()
{
    if(strcmp(USER(),"root") == 0){return '#';}
    return '$';
}
void InputCommend()
{
    flag = 0;
    printf("[%s@%s %s]%c",USER(),HOSTNAME(),PWD(),CMD());
    fgets(commend,SIZE,stdin);
    commend[strlen(commend)-1] = '\0';
}
void CheckRedir()
{
    redir = NONE_REDIR;
    filepath = NULL;
    int pos = strlen(commend)-1;
    while(pos>=0)
    {
        if(commend[pos] == '>')
        {
            if(commend[pos-1] == '>')
            {
                redir = APPEND_REDIR;
                commend[pos-1] = STREND;
                pos++;
                IgnSpace(pos);
                filepath = (char*)commend+pos;
                break;
            }
            else
            {
                redir = STDOUT_REDIR;
                commend[pos++] = STREND;
                IgnSpace(pos);
                filepath = (char*)commend+pos;
                break;
            }
        }
        else if (commend[pos] == '<')
        {
            redir = STDIN_REDIR;
            commend[pos++] = STREND;
            IgnSpace(pos);
            //strcpy(filepath,commend+pos);
            filepath = (char*)commend+pos;
            break;
        }
        else{pos--;}
    }
}

void Redir()
{
    int fd = -1;
    umask(0);
    if(redir == STDIN_REDIR)
    {
        fd = open(filepath,O_RDONLY);
        dup2(fd,0);
    }
    else if(redir == STDOUT_REDIR)
    {
        fd = open(filepath,O_WRONLY|O_CREAT|O_TRUNC,0666);
        dup2(fd,1);
    }
    else if(redir == APPEND_REDIR)
    {
        fd = open(filepath,O_WRONLY|O_CREAT|O_APPEND,0666);
        dup2(fd,1);
    }
}
void Split()
{
    CheckRedir();
    int i = 0;
    argv[i++] =  strtok(commend," ");
    while(argv[i] = strtok(NULL," "))
    {
        i++;
    }
}

int BuildinCmd()
{
    int ret = 0;//返回是否为内建命令
    if(strcmp(argv[0],"cd") == 0)
    {
        ret = 1;
        char* target = argv[1];
        if(!target){target = HOME();}
        chdir(target);
        char tmp[SIZE];
        getcwd(tmp,SIZE);
        snprintf(pwd,SIZE,"PWD=%s",tmp);
        putenv(pwd);
    }
    else if(strcmp(argv[0],"echo") == 0)
    {
        ret = 1;
        if(!argv[1]){printf("\n");}
        if(argv[1][0] == '$')
        {
            if(argv[1][1] == '?')
            {
                printf("%d\n",WEXITSTATUS(status));
            }
            else
            {
                printf("%s\n",getenv(&argv[1][1]));
            }
        }
        else
        {
            printf("%s\n",argv[1]);
        }
    }
    return ret;
}
void Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        Redir();
        if(strcmp(argv[0],"ll") == 0)
        {
            int i = 0;
            argv[0] = (char*)"ls";
            for(; argv[i]!=NULL; i++){}
            argv[i++] = (char*)"-l";
            argv[i] = NULL;
        }
        if(strcmp(argv[0],"ls") == 0)
        {
            int i = 0;
            for(; argv[i]!=NULL; i++){}
            argv[i++] = (char*)"--color";
            argv[i] = NULL;
        }
        execvp(argv[0],argv);
        exit(1);
    }
    //int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid == id)
    {
        return;
    }

}
int main()
{
    while(1)
    {
        //1.等待输入命令
        InputCommend();
        //2.分割指令
        Split();
        //3.处理内建命令
        flag = BuildinCmd();
        //4.运行指令
        if(!flag){Execute();}
    }
    return 0;
}
